package handler

import (
	"context"
	"errors"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"
	"gorm.io/gorm"

	proto "mxshop_srvs/goods_srv/proto/gen/v1"
)

func (s *Service) CreateCategoryBrand(_ context.Context, req *proto.CategoryBrandRequest) (resp *proto.CategoryBrandResponse, err error) {
	category, err := s.DB.GetCategory(req.CategoryId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.NotFound, "")
		}
		return nil, status.Error(codes.Internal, "")
	}
	brand, err := s.DB.GetBrandByID(req.BrandId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.NotFound, "")
		}
		return nil, status.Error(codes.Internal, "")
	}

	count, err := s.DB.CategoryBrandExists(category.ID, brand.ID)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	if count > 0 {
		return nil, status.Error(codes.AlreadyExists, "")
	}

	categoryBrand, err := s.DB.CreateCategoryBrand(category.ID, brand.ID)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	return &proto.CategoryBrandResponse{Id: categoryBrand.ID}, nil
}

func (s *Service) CategoryBrandList(_ context.Context, req *proto.CategoryBrandFilterRequest) (resp *proto.CategoryBrandListResponse, err error) {
	total, err := s.DB.GetCategoryBrandCount()
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}

	categoryBrandList, err := s.DB.CategoryBrandList(req)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}

	var data []*proto.CategoryBrandResponse
	for _, categoryBrand := range categoryBrandList {
		data = append(data, &proto.CategoryBrandResponse{
			Id: categoryBrand.ID,
			Brand: &proto.BrandInfoResponse{
				Id:   categoryBrand.Brands.ID,
				Name: categoryBrand.Brands.Name,
				Logo: categoryBrand.Brands.Logo,
			},
			Category: &proto.CategoryInfoResponse{
				Id:             categoryBrand.Category.ID,
				Name:           categoryBrand.Category.Name,
				ParentCategory: categoryBrand.Category.ParentCategoryID,
				Level:          categoryBrand.Category.Level,
				IsTab:          categoryBrand.Category.IsTab,
			},
		})
	}
	return &proto.CategoryBrandListResponse{
		Total: int32(total),
		Data:  data,
	}, nil
}

func (s *Service) GetCategoryBrandList(_ context.Context, req *proto.CategoryInfoRequest) (*proto.BrandListResponse, error) {
	_, err := s.DB.GetCategory(req.Id)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.InvalidArgument, "")
		}
		return nil, status.Error(codes.Internal, "")
	}

	categoryBrandList, err := s.DB.GetCategoryBrandList(req.Id)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}

	var data []*proto.BrandInfoResponse
	for _, categoryBrand := range categoryBrandList {
		data = append(data, &proto.BrandInfoResponse{
			Id:   categoryBrand.BrandsID,
			Name: categoryBrand.Brands.Name,
			Logo: categoryBrand.Brands.Logo,
		})
	}
	return &proto.BrandListResponse{Data: data}, nil
}

func (s *Service) UpdateCategoryBrand(_ context.Context, req *proto.CategoryBrandRequest) (*emptypb.Empty, error) {
	count, err := s.DB.CategoryBrandByID(req.Id)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	if count == 0 {
		return nil, status.Error(codes.InvalidArgument, "")
	}

	row, err := s.DB.CategoryBrandExists(req.CategoryId, req.BrandId)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	if row == 1 {
		return nil, status.Error(codes.InvalidArgument, "")
	}

	_, err = s.DB.GetCategory(req.CategoryId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.InvalidArgument, "")
		}
		return nil, status.Error(codes.Internal, "")
	}
	_, err = s.DB.GetBrandByID(req.BrandId)
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, status.Error(codes.InvalidArgument, "")
		}
		return nil, status.Error(codes.Internal, "")
	}

	row, _, err = s.DB.UpdateCategoryBrand(req)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	if row != 1 {
		return nil, status.Error(codes.Internal, "")
	}
	return &emptypb.Empty{}, nil
}

func (s *Service) DeleteCategoryBrand(_ context.Context, req *proto.CategoryBrandRequest) (resp *emptypb.Empty, err error) {
	row, err := s.DB.DeleteCategoryBrand(req.Id)
	if err != nil {
		return nil, status.Error(codes.Internal, "")
	}
	if row == 0 {
		return nil, status.Error(codes.NotFound, "")
	}
	return &emptypb.Empty{}, nil
}
